package com.wn.sk.product.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wn.common.api.Result;
import com.wn.common.api.order.contants.OrderConstant;
import com.wn.common.api.order.dto.OrderDto;
import com.wn.common.api.order.dto.OrderPayDto;
import com.wn.common.api.order.vo.OrderVo;
import com.wn.common.api.status.impl.ResultCode;
import com.wn.sk.order.client.OrderFeignClient;
import com.wn.sk.product.core.contant.RedisContents;
import com.wn.sk.product.core.entity.Product;
import com.wn.sk.product.core.entity.PromotionSeckill;
import com.wn.sk.product.core.entity.PromotionStatus;
import com.wn.sk.product.core.exception.Asserts;
import com.wn.sk.product.core.mapper.PromotionSeckillMapper;
import com.wn.sk.product.core.product.OrderProducer;
import com.wn.sk.product.core.service.IProductService;
import com.wn.sk.product.core.service.IPromotionSeckillService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wn.sk.product.core.vo.PaymentVo;
import com.wn.sk.product.core.vo.PromotionVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * <p>
 * 秒杀活动表 服务实现类
 * </p>
 *
 * @author yellow docker
 * @since 2022-09-02
 */
@Service
@Slf4j
public class PromotionSeckillServiceImpl extends ServiceImpl<PromotionSeckillMapper, PromotionSeckill> implements IPromotionSeckillService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Autowired
    private IProductService productService;

    @Autowired
    private OrderProducer orderProducer;

    @Override
    public Result submitOrder(Integer promotionId, String userId) {

        /**
         * 下单的详情
         *  1. 根据秒杀活动id查询，获取秒杀活动的状态，根据状态判断
         *  2. 判断：一个用户只能购买一个类型的秒杀商品
         *  3. 秒杀库存减少
         *  4.生成订单：通过Openfeign远程调用订单接口..  (其他的服务成功)
         *  5. 生成订单后的记录    (这里失败了) ？ (其他的服务的数据库不能改变)
         */
        //通过id 拿到产品
        PromotionSeckill promotionSeckill = this.getById(promotionId); //和业务代码没关系 为了程序健壮而已
        if (promotionSeckill == null){
            log.error("秒杀活动不存在...");
            return Result.error(ResultCode.RESULE_DATA_NONE);
        }
        if (promotionSeckill.getStatus() == PromotionStatus.UN_START ){
            log.error("秒杀活动未开始...");
            return Result.error(ResultCode.RESULE_DATA_NONE);
        }
        if (promotionSeckill.getStatus() == PromotionStatus.FINISH ){
            log.error("秒杀活动以结束...");
            return Result.error(ResultCode.RESULE_DATA_NONE);
        }

        //判断 当前的用户是否以购买了这个商品
        //sismember seckill:user:101 1 判断用户是否够买了产品
        Boolean member = redisTemplate.opsForSet().isMember(RedisContents.PRODUCT_KILL_USER + userId, promotionId);
        if (member){
            log.error("已购买活动商品,不能再买...");
            return Result.error(ResultCode.RESULE_DATA_NONE);
        }
        //生产订单  openFeign调用
        log.error("远程调用 拿到 订单编号...");
        //1.远程调用

        //1.准备参数
        OrderDto orderDto = new OrderDto();
        orderDto.setUserId(userId);

        Product product = productService.getById(promotionSeckill.getProductId());

        //这里是商品的信息
        orderDto.setProductId(product.getId());
        orderDto.setProductPic(product.getPic());
        orderDto.setProductName(product.getTitle());
        orderDto.setPrice(product.getPrice());
        //活动价格
        orderDto.setPromotionPrice(product.getPromotionPrice());

        //2 方法调用传递参数
        Result<String> result = orderFeignClient.createOrder(orderDto);

        // 订单的编号
        String orderSn = result.getData();

        if (!StringUtils.isEmpty(orderSn)){
            //秒库存       product:kill:count:1  [871,871,871]
            Integer value = (Integer) redisTemplate.opsForList().leftPop(RedisContents.PRODUCT_KILL_COUNT + promotionId);
            if (value == null){
                log.error("库存已没有...");
                //库存没有 (通过 ps_order 表中的数据要就进行回滚 (分布式事务 ))
                return Result.error(ResultCode.RESULE_DATA_NONE);
            }
        }

        //记录 当前用户购买的信息
//       sadd seckill:user:100 1
//​		 sadd seckill:user:100 2
//​		 sadd seckill:user:100 3

        redisTemplate.opsForSet().add(RedisContents.PRODUCT_KILL_USER+userId,promotionId);

        PromotionVo promotionVo = new PromotionVo();
        promotionVo.setUserId(userId);
        promotionVo.setOrderNo(orderSn);

        return Result.common(promotionVo);
    }

    /**
     * 确认订单的业务
     * @param orderPayDto
     * @param userId
     * @return
     */
    @Override
    public PaymentVo confirmOrder(OrderPayDto orderPayDto, String userId) {

        //远程查询订单 信息
        Result<OrderVo> result  =
                orderFeignClient.getOrderBySn(orderPayDto.getOrderSn());
        OrderVo vo = result.getData();

//        //订单状态：0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_INVALID)){//5
            Asserts.failed("订单已失效");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_CLOSED)){//4
            Asserts.failed("订单已经关闭");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_FINISH)){//3
            Asserts.failed("订单已经完成");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_SHIP)){//2
            Asserts.failed("订单已经发货");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_UNSHIP)){//1 ?
            Asserts.failed("订单待发货");
        }

        //查询商品ID
        LambdaQueryWrapper<PromotionSeckill> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(PromotionSeckill::getProductId);
        queryWrapper.eq(PromotionSeckill::getId,orderPayDto.getPromotionId());
        PromotionSeckill ps = baseMapper.selectOne(queryWrapper);

        //组装 orderPayDto 信息
        orderPayDto.setProductId(ps.getProductId());//商品Id，如果订单失效需要还原redis库存

        //发送消息到MQ  （ 付款的延时操作 ）
        //创建队列 创建交换机  和死信队列绑定(可以在config中写 ，可以在 消费者哪里写 )
        orderProducer.sendOrder(orderPayDto);

        PaymentVo paymentVo = new PaymentVo();

        paymentVo.setPromotionId(orderPayDto.getPromotionId());
        paymentVo.setOrderSn(vo.getOrderSn());
        paymentVo.setUserId(userId);
        paymentVo.setTotalAmount(vo.getTotalAmount());
        return paymentVo;
    }

    /**
     * 付款操作
     * @param orderPayDto
     * @return
     */
    @Override
    public Integer payOrder(OrderPayDto orderPayDto) {

        // 订单的状态的修改
        // mysql中的库存减少

        //进行付款操作  后面集成给 大家看下
        //工作中 别人写好了接口 你直接调用给参数就可以
        log.info("进行付款成功...");

        //更新订单状态，调用订单微服务
        Result<Integer> result = orderFeignClient.update(orderPayDto.getOrderSn());
        if(result.getCode() == 500){
            Asserts.failed("更新失败...");
        }
        //扣减库存
        int count = baseMapper.updateStore(orderPayDto.getPromotionId());
        if(count<=0){
            Asserts.failed("库存扣减失败");
        }

        //如果产品库存和 秒杀库存看什么关系?
        // 产品库存和 库存 包含关系 需要减
        // 产品库存 如果是 独立的不用减

        return result.getData();

    }
}
